import { effect } from '../effect/effect.js';
import { TrackOpTypes, TriggerOpTypes } from '../utils/types.js';
import track from '../effect/track.js';
import trigger from '../effect/trigger.js';

/**
 * 归一化计算属性参数
 * @param {function|object<{getter: function, setter?: function}>} getterOrOptions 计算属性的 getter 函数或选项对象
 * @returns 归一化后的参数对象，包含 getter 和 setter 函数
 */
const normalizeParams = (getterOrOptions) => {
  let getter, setter;
  if (typeof getterOrOptions === 'function') {
    getter = getterOrOptions;
    setter = () => {
      console.warn('计算属性只能读取，不能写入');
    };
  } else {
    getter = getterOrOptions.getter;
    setter = getterOrOptions.setter;
  }
  return {
    getter,
    setter,
  };
};

/**
 * 计算属性函数
 * @param {function|object<{getter: function, setter?: function}>} getterOrOptions 计算属性的 getter 函数或选项对象
 */
export function computed(getterOrOptions) {
  // 参数归一化
  const { getter, setter } = normalizeParams(getterOrOptions);
  let target;
  let value,
    dirty = true;
  const computedEffect = effect(getter, {
    lazy: true,
    scheduler: () => {
      dirty = true;
      // 触发依赖更新
      trigger(target, TriggerOpTypes.SET, 'value');
    },
  });
  target = {
    get value() {
      // 依赖收集
      track(this, TrackOpTypes.GET, 'value');
      if (dirty) {
        value = computedEffect();
        dirty = false;
      }
      return value;
    },
    set value(newVal) {
      setter(newVal);
    },
  };
  return target;
}
